using LFrameworkAOT;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

namespace LFramework
{
    /// <summary>
    /// Http访问器
    /// </summary>
    public class HttpRoutine
    {
        #region 属性

        /// <summary>
        /// http 请求结束回调
        /// </summary>
        private Action<HttpCallBackArgs> m_CallBack;

        /// <summary>
        /// Http请求回调数据
        /// </summary>
        private HttpCallBackArgs m_CallBackArgs;

        /// <summary>
        /// 是否繁忙
        /// </summary>
        public bool IsBusy { get; private set; }

        /// <summary>
        /// 当前重试次数
        /// </summary>
        private int m_CurrRetry = 0;

        private string m_Url;
        private string m_Json;
        private byte[] m_ByteArg;
        private Dictionary<string, string> m_AddHeaderDic = null;
        private bool m_IsAddDefaultHeader = true;

        //是否json数据格式
        private bool m_IsJsonFormat;

        /// <summary>
        /// 发送的数据
        /// </summary>
        private Dictionary<string, object> m_Dic;
        #endregion

        public HttpRoutine()
        {
            m_CallBackArgs = new HttpCallBackArgs();
            m_Dic = new Dictionary<string, object>();
        }
        public static HttpRoutine Create()
        {
            return new HttpRoutine();
        }

        #region SendData 发送web数据
        /// <summary>
        /// 发送web数据
        /// </summary>
        /// <param name="url"></param>
        /// <param name="callBack"></param>
        /// <param name="isPost"></param>
        /// <param name="isGetData">是否获取字节数据</param>
        /// <param name="dic"></param>
        public void Get(string url, Action<HttpCallBackArgs> callBack = null)
        {
            if (IsBusy) return;
            IsBusy = true;

            m_Url = url;
            m_CallBack = callBack;

            GetUrl(m_Url);
        }

        public void PostByJson(string url, string json = null, Action<HttpCallBackArgs> callBack = null, Dictionary<string, string> addHeaderDic = null, bool isAddDefaultHeader = true)
        {
            if (IsBusy) return;
            IsBusy = true;

            m_Url = url;
            m_CallBack = callBack;
            m_Json = json;
            m_AddHeaderDic = addHeaderDic;
            m_IsAddDefaultHeader =isAddDefaultHeader;
            m_IsJsonFormat = true;

            PostUrlByJson(m_Url);
        }

        public void PostByBytes(string url, byte[] byteArg, Action<HttpCallBackArgs> callBack = null, Dictionary<string, string> addHeaderDic = null, bool isAddDefaultHeader = true)
        {
            if (IsBusy) return;
            IsBusy = true;

            m_Url = url;
            m_CallBack = callBack;
            m_ByteArg = byteArg;
            m_AddHeaderDic = addHeaderDic;
            m_IsAddDefaultHeader = isAddDefaultHeader;
            m_IsJsonFormat = false;

            PostUrlByByte(m_Url);
        }
        #endregion

        #region GetUrl Get请求
        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="url"></param>
        private void GetUrl(string url)
        {
            Debug.Log(string.Format("Get请求:{0}, {1}次重试", m_Url, m_CurrRetry));
            UnityWebRequest data = UnityWebRequest.Get(url);
            GameLaunch.Instance.StartCoroutine(Request(data));
        }
        #endregion

        #region PostUrl Post请求

        private void SetHeads(UnityWebRequest unityWeb) 
        {
            long t = (long)Time.unscaledTime;//SystemModel.Instance.CurrServerTime;

            unityWeb.SetRequestHeader("deviceIdentifier", DeviceUtil.DeviceIdentifier);
            unityWeb.SetRequestHeader("deviceModel", DeviceUtil.DeviceModel);
            unityWeb.SetRequestHeader("sign", EncryptUtil.Md5(string.Format("{0}:{1}", t, DeviceUtil.DeviceIdentifier)));
            unityWeb.SetRequestHeader("t", t.ToString());
        }

        /// <summary>
        /// Post请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="json"></param>
        private void PostUrlByJson(string url)
        {
            UnityWebRequest unityWeb = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST);
            unityWeb.downloadHandler = new DownloadHandlerBuffer();
            if (!string.IsNullOrWhiteSpace(m_Json))
            {
                unityWeb.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(m_Json));

                if (m_AddHeaderDic != null) 
                {
                    foreach (KeyValuePair<string,string> item in m_AddHeaderDic) 
                    {
                        unityWeb.SetRequestHeader(item.Key.Trim(), item.Value.Trim());
                    }
                }

                if (m_IsAddDefaultHeader)
                    SetHeads(unityWeb);

                unityWeb.SetRequestHeader("Content-Type", "application/json");
            }

            Debug.Log(string.Format("Post请求:{0}, {1}次重试==>>{2}", m_Url, m_CurrRetry, m_Json));
            GameLaunch.Instance.StartCoroutine(Request(unityWeb));
        }

        /// <summary>
        /// Post请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="json"></param>
        private void PostUrlByByte(string url)
        {
            UnityWebRequest unityWeb = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST);
            unityWeb.downloadHandler = new DownloadHandlerBuffer();

            unityWeb.uploadHandler = new UploadHandlerRaw(m_ByteArg);

            if (m_AddHeaderDic != null)
            {
                foreach (var item in m_AddHeaderDic)
                    unityWeb.SetRequestHeader(item.Key, item.Value);
            }

            if (m_IsAddDefaultHeader)
                SetHeads(unityWeb);
            unityWeb.SetRequestHeader("Content-Type", "application/x-protobuf");

            Debug.Log(string.Format("Post请求:{0}, {1}次重试==>>{2}", m_Url, m_CurrRetry, m_Json));
            GameLaunch.Instance.StartCoroutine(Request(unityWeb));
        }
        #endregion

        #region Request 请求服务器
        /// <summary>
        /// 请求服务器
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private IEnumerator Request(UnityWebRequest data)
        {
            data.timeout = 60;
            yield return data.SendWebRequest();
            if (data.result == UnityWebRequest.Result.Success)
            {
                IsBusy = false;
                m_CallBackArgs.HasError = false;
                m_CallBackArgs.Value = data.downloadHandler.text;
                m_CallBackArgs.Data = data.downloadHandler.data;
            }
            else
            {
                //报错了 进行重试
                if (m_CurrRetry > 0) yield return new WaitForSeconds(GameLaunch.ParamsSettings.HttpRetryInterval);
                m_CurrRetry++;
                if (m_CurrRetry <= GameLaunch.ParamsSettings.HttpRetry)
                {
                    switch (data.method)
                    {
                        case UnityWebRequest.kHttpVerbGET:
                            GetUrl(m_Url);
                            break;
                        case UnityWebRequest.kHttpVerbPOST:
                            if(m_IsJsonFormat)
                                PostUrlByJson(m_Url);
                            else
                                PostUrlByByte(m_Url);
                            break;
                    }
                    data.Dispose();
                    data = null;
                    yield break;
                }

                IsBusy = false;
                m_CallBackArgs.HasError = true;
                m_CallBackArgs.Value = data.error;
            }

            if (!string.IsNullOrWhiteSpace(m_CallBackArgs.Value)) Debug.Log( string.Format("WebAPI回调:{0}, ==>>{1}", m_Url, m_CallBackArgs.ToJson()));
            m_CallBack?.Invoke(m_CallBackArgs);

            m_CurrRetry = 0;
            m_Url = null;
            if (m_Dic != null)
            {
                m_Dic.Clear();
            }
            m_CallBackArgs.Data = null;
            data.Dispose();
            data = null;
        }
        #endregion
    }
}